package top.yangyitao.lockManager.lock.jvm;

import top.yangyitao.lockManager.lock.LockSubject;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author eetal
 */
public class JVMLockSubject extends LockSubject<Object> {
    private static Map<String,ReentrantLock> jvmSyncLockMap = new ConcurrentHashMap<String, ReentrantLock>();

    private boolean alive = false;
    private String sync;//Object.toString().intern()

    private ReentrantLock reentrantLock;

    protected JVMLockSubject(){}

    @Override
    public void initialize(Object obj) {
        String _sync = obj.toString().intern();
        sync = _sync;
        synchronized (_sync) {
            if (jvmSyncLockMap.containsKey(_sync)) {
                reentrantLock = jvmSyncLockMap.get(_sync);
            } else {
                reentrantLock = new ReentrantLock();
            }
            jvmSyncLockMap.put(_sync, reentrantLock);//防止刚好别的线程解锁完
            alive = true;
        }
    }

    @Override
    public void destroy() {
        sync = null;
        reentrantLock = null;
        alive = false;
    }

    @Override
    public boolean isHeldByCurrentThread() {
        return reentrantLock == null?false:reentrantLock.isHeldByCurrentThread();
    }

    @Override
    public void lock() {
        try {
            //避免互相占据死锁
            if(!reentrantLock.tryLock(3500, TimeUnit.MILLISECONDS)){
                throw new RuntimeException("获取锁失败");
            }
        }catch (InterruptedException e){
            throw new RuntimeException("获取锁失败");
        }
    }

    @Override
    public void tryLock() {
        if(!reentrantLock.tryLock()){
            throw new RuntimeException("获取锁失败");
        }
    }

    @Override
    public void unlock(){
        reentrantLock.unlock();
        synchronized (sync) {
            if (!reentrantLock.isLocked()) {
                //全部释放
                jvmSyncLockMap.remove(sync);
            }
        }
    }

    @Override
    public boolean equalKey(Object o) {
        return sync.equals(o);
    }

    @Override
    public boolean isAlive() {
        return alive;
    }
}
